/*
 * Copyright (c) 2017-2019, Lindenis Tech. Ltd.
 * All rights reserved.
 *
 * File:
 *
 * Description:
 *
 * Author:
 *      xiaoshujun@lindeni.com
 *
 * Create Date:
 *      2019/11/04
 *
 * History:
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.h>
#include <sys/stat.h>

#include "osal_common.h"
#include "vdec_wrapper.h"
#include "lindcomponent.h"
#include "lindjpeg.h"

#include "osal_log.h"

#define SCREEN_W    720
#define SCREEN_H    1280
static int g_screen_w           = SCREEN_W;
static int g_screen_h           = SCREEN_H;
static int g_max_w              = 1920;
static int g_max_h              = 1080;
static char * g_pic_file        = NULL;
static int g_rotate             = ROTATE_DEGREE_NONE;

#define MAX_PLAYER      4
static int g_running            = 0;
static pthread_t g_input_tid    = 0;
static int g_multi_player       = 1;
static hdl_lindjpg_t g_jpeg_player[MAX_PLAYER] = {0};

#define MAX_JPG_CNT 8
static char g_jpg_slide[MAX_JPG_CNT][128] = {0};
static int g_slide_cnt = 0;
static int g_show_ms = 5000;    // 5s

int get_jpg_list(char * base_path)
{
    DIR *dir;
    struct dirent *ptr;
    int count = 0;

    if ((dir = opendir(base_path)) == NULL)
    {
        loge("This is not a directory(%s).", base_path);
        exit(1);
    }

    while ((ptr = readdir(dir)) != NULL)
    {
        if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0)
        {
            continue;
        }
        else if(ptr->d_type == 8)    // file
        {
            if (strstr(ptr->d_name, ".jpg"))
            {
                sprintf(g_jpg_slide[count], "%s/%s", base_path, ptr->d_name);
                logd("got jpg %d: %s", count, g_jpg_slide[count]);
                count++;
                if (count >= MAX_JPG_CNT) {
                    break;
                }
            }
        }
        else if(ptr->d_type == 10)    // link file
        {
            continue;
        }
        else if(ptr->d_type == 4)    // dir
        {
            continue;
        }
    }
    closedir(dir);

    return count;
}


static int sample_jpeg_on_input_key()
{
    signed char key_val;
    int ret = wait_input_char(&key_val, 500000);    // 500ms time out
    if (ret < 0) {
        return -1;
    } else if (ret == 0) {
        if (g_running == 0) {
            return -1;
        }
        return 0;
    }

    if (key_val > 0 && key_val)
    {
        if (key_val == '\n') {
            printf("\n");
        } else {
            printf("********* key_val: %c ********** \n", key_val);
        }

        if (key_val == 'q' || key_val == 'Q')
        {
            g_running = 0;
            return -1;
        }
    }

    return 0;
}

static void * sample_jpeg_input_key_thread(void *param)
{
    while(1)
    {
        if (sample_jpeg_on_input_key())
            break;
    }

    logd("input_thread exit ");

    return 0;
}

int sample_jpeg_slide()
{
    int ret = 0;
    hdl_lindjpg_t h_jpg = (hdl_lindjpg_t)NULL;
    av_frame2_t * p_out = NULL;
    char * pic_file = NULL;
    int index = 0;

    h_jpg = lindjpg_create();
    if (h_jpg == (hdl_lindjpg_t)NULL)
    {
        loge("lindjpg_create failed");
        return -1;
    }

    while (g_running)
    {
        pic_file = g_jpg_slide[index++ % g_slide_cnt];
        logi("index: %d, %s", index, pic_file);
        ret = lindjpg_decode(h_jpg, pic_file, &p_out, g_max_w, g_max_h);
        if (ret < 0)
        {
            loge("lindjpg_decode failed");
            goto __exit__;
        }

        logi("jpeg(%d) decode success, pic: %dx%d", index, p_out->width, p_out->height);

        lindjpg_render_cfg_t config = {0};
        config.rotate = g_rotate;
        ret = lindjpg_render(h_jpg, &config, p_out);
        if (ret < 0)
        {
            loge("lindjpg_render failed");
            lindjpg_release(h_jpg, p_out);
            goto __exit__;
        }

        usleep(g_show_ms * 1000);

        lindjpg_release(h_jpg, p_out);
    }

__exit__:
    lindjpg_destroy(h_jpg);
    return 0;
}

static void * slide_jpeg_thread(void *param)
{
    sample_jpeg_slide();
    return 0;
}

int sample_jpeg_player(const char * pic_file, int index)
{
    int ret = 0;
    hdl_lindjpg_t h_jpg = (hdl_lindjpg_t)NULL;
    av_frame2_t * p_out = NULL;

    g_jpeg_player[index] = lindjpg_create();
    h_jpg = g_jpeg_player[index];
    if (h_jpg == (hdl_lindjpg_t)NULL)
    {
        loge("lindjpg_create failed");
        return -1;
    }

    int pic_w = 0, pic_h = 0;
    ret = lindjpg_get_mediainfo(pic_file, &pic_w, &pic_h);
    if (ret < 0) {
        goto __exit__;
    }
    logi("pic size: %dx%d, request max size: %dx%d", pic_w, pic_h, g_max_w, g_max_h);

    ret = lindjpg_decode(h_jpg, pic_file, &p_out, g_max_w, g_max_h);
    if (ret < 0)
    {
        loge("lindjpg_decode failed");
        goto __exit__;
    }

    logi("jpeg decode success, pic: %dx%d", p_out->width, p_out->height);

    lindjpg_render_cfg_t config = {0};
    config.rotate = g_rotate;
    switch(index){
        case -1:
            config.disp_pos.top = 0;
            config.disp_pos.left = 0;
            config.disp_pos.width = 0;
            config.disp_pos.height = 0;
            break;
        case 0:
            config.disp_pos.top = 0;
            config.disp_pos.left = 0;
            config.disp_pos.width = g_screen_w / 2;
            config.disp_pos.height = g_screen_h / 2;
            break;
        case 1:
            config.disp_pos.top = g_screen_h / 2;
            config.disp_pos.left = 0;
            config.disp_pos.width = g_screen_w / 2;
            config.disp_pos.height = g_screen_h / 2;
            break;
        case 2:
            config.disp_pos.top = 0;
            config.disp_pos.left = g_screen_w / 2;
            config.disp_pos.width = g_screen_w / 2;
            config.disp_pos.height = g_screen_h / 2;
            break;
        case 3:
            config.disp_pos.top = g_screen_h / 2;
            config.disp_pos.left = g_screen_w / 2;
            config.disp_pos.width = g_screen_w / 2;
            config.disp_pos.height = g_screen_h / 2;
            break;
        default:
            loge("error index: %d", index);
            goto __exit1__;
    };

    if (g_multi_player == 1) {
        // force full screen display
        config.disp_pos.width = 0;
        config.disp_pos.height = 0;
    }

    ret = lindjpg_render(h_jpg, &config, p_out);
    if (ret < 0)
    {
        loge("lindjpg_render failed");
        goto __exit1__;
    }

    usleep(g_show_ms * 1000);

__exit1__:
    lindjpg_release(h_jpg, p_out);

__exit__:
    lindjpg_destroy(h_jpg);
    g_jpeg_player[index] = (_handle_t)NULL;
    return 0;
}

static void * multi_jpeg_thread(void *param)
{
    int index = *(int *)param;
    free(param);

    logi(" ********* player[%d] running ", index);

    sample_jpeg_player(g_pic_file, index);

    logi(" ********* player[%d] exit ", index);

    int i = 0;
    for (i = 0; i < MAX_PLAYER; i++)
    {
        if (g_jpeg_player[index]) {
            break;
        }
    }
    if (i == MAX_PLAYER) {
        logd("all players exit");
        g_running = 0;
    }

    return 0;
}

static void print_usage(char * this)
{
    printf("\033[32m    Usage: \033[0m\n");
    printf("\033[32m        %s [jpg_file]\033[0m\n", this);
    printf("\033[32m    other options parameters:\033[0m\n");
    printf("\033[32m            -h [help]           : print this usage \033[0m\n");
    printf("\033[32m            -s [screen_w  h]    : screen width & height, default '1280 720' \033[0m\n");
    printf("\033[32m            -m [multi_player]   : number of player instance, '1, 2, 3, 4', default: 1 \033[0m\n");
    printf("\033[32m            -r [rotate]         : video rotation degree, '0, 90, 180, 270', default: 0 \033[0m\n");
    printf("\033[32m            -t [tm_ms]          : duration of each picture, default: 5000 \033[0m\n");
    printf("\033[32m            -max [max_w, h]     : max output size \033[0m\n");
    printf("\033[32m            -slide              : slide mode to play all jpg in 'argv[1]' \033[0m\n");
    printf("\033[32m        such as: %s /mnt/extsd/1.jpg \033[0m\n", this);
    printf("\033[32m             or: %s /mnt/extsd/1.jpg -m 4 -r 90 \033[0m\n", this);
    printf("\033[32m             or: %s /mnt/extsd/ -slide -t 1000 -r 90 \033[0m\n", this);
}

#ifdef MELIS_OS
static int main_sample_jpeg(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
{
	char pic_file[128] = "/sdcard/test.jpg";
    int i = 0;
    pthread_t tid[4] = {0};
    int ret = 0;
    int rotate = 0;
    int fps = 0;
    int codec = AV_ENC_TYPE_H264;

    if (argc == 2 && strcmp(argv[1], "-h"))
    {
        strcpy(pic_file, argv[1]);
    }
    else if (argc >= 3)
    {
        strcpy(pic_file, argv[1]);

        for (i = 2; i < argc; )
        {
            if (!strcmp(argv[i], "-m"))
            {
                g_multi_player = atoi(argv[i + 1]);
                i += 2;
                if (g_multi_player > MAX_PLAYER) {
                    logw("multi players should less than %d", MAX_PLAYER);
                    g_multi_player = MAX_PLAYER;
                }
            }
            else if (!strcmp(argv[i], "-r"))
            {
                rotate = atoi(argv[i + 1]);
                i += 2;
            }
            else if (!strcmp(argv[i], "-s"))
            {
                g_screen_w = atoi(argv[i + 1]);
                g_screen_h = atoi(argv[i + 2]);
                i += 3;
            }
            else if (!strcmp(argv[i], "-t"))
            {
                g_show_ms = atoi(argv[i + 1]);
                i += 2;
            }
            else if (!strcmp(argv[i], "-max"))
            {
                g_max_w = atoi(argv[i + 1]);
                g_max_h = atoi(argv[i + 2]);
                i += 3;
            }
            else if (!strcmp(argv[i], "-slide"))
            {
                g_slide_cnt = get_jpg_list(pic_file);
                if (g_slide_cnt <= 0) {
                    logw("do not fild jpg file in '%s'", pic_file);
                    return 0;
                }
                i += 1;
            }
            else
            {
                i++;
            }
        }
    }
    else
    {
        print_usage(argv[0]);
        return 0;
    }

    g_pic_file = pic_file;
    g_running = 1;
    switch(rotate)
    {
        case 0:
            g_rotate = ROTATE_DEGREE_NONE;
            break;
        case 90:
            g_rotate = ROTATE_DEGREE_90;
            break;
        case 180:
            g_rotate = ROTATE_DEGREE_180;
            break;
        case 270:
            g_rotate = ROTATE_DEGREE_270;
            break;
        default:
            g_rotate = ROTATE_DEGREE_NONE;
            logw("invalid rotate(%d), force to 0", rotate);
            break;
    }

    if (g_slide_cnt > 0)
    {
        logi("slide file: %s, multi player: %d, rotate: %d", pic_file, rotate);
        ret = pthread_create(&tid[0], NULL, slide_jpeg_thread, NULL);
        if (ret) {
            loge("slide_jpeg_thread fail! ret: %d ", ret);
            return -1;
        }
    }
    else
    {
        logi("play file: %s, multi player: %d, rotate: %d", pic_file, g_multi_player, rotate);
        for (i = 0; i < g_multi_player; i++)
        {
            int * index = malloc(sizeof(int));
            *index = i;
            ret = pthread_create(&tid[i], NULL, multi_jpeg_thread, (void *)index);
            if (ret) {
                loge("multi_jpeg_thread fail! ret: %d ", ret);
                return -1;
            }
        }
    }

    ret = pthread_create(&g_input_tid, NULL, sample_jpeg_input_key_thread, NULL);
    if (ret) {
        loge("pthread_create msg thread fail! ret: %d ", ret);
        exit(-1);
    }
    pthread_join(g_input_tid, 0);

    for (i = 0; i < MAX_PLAYER; i++)
    {
        if (tid[i]) {
            pthread_join(tid[i], 0);
        }
    }

    logd("main exit ok");
	return 0;
}

#ifdef MELIS_OS
FINSH_FUNCTION_EXPORT_ALIAS(main_sample_esplayer, __cmd_sample_jpeg, jpeg player);
#endif
